﻿using Cheems.Interface.SQL;
using System.Linq.Expressions;
using LiteDB;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Cheems.Service.SQL
{
    public class LitedbRepository<TEntity> : IBaseRepository<TEntity> where TEntity : class
    {
        private string _connectionString;
        private LiteDatabase _db;
        private ILiteCollection<TEntity> _collection; 
        private List<TEntity> _cache = new List<TEntity>();
        private Timer _timer;

        public LitedbRepository(string connectionString)
        {
            _connectionString = connectionString;
            _db = new LiteDatabase(_connectionString);
            _collection = _db.GetCollection<TEntity>(typeof(TEntity).Name);

            _timer = new Timer(InsertDataFromCache, null, Timeout.Infinite, Timeout.Infinite); // 初始化定时器
        }

        public int CurrentDataSize => (int)_collection.Count();

        public void UpdateConnectionString(string connectionString)
        {
            _connectionString = connectionString;
            _db = new LiteDatabase(_connectionString);
            _collection = _db.GetCollection<TEntity>(typeof(TEntity).Name);
        }

        public async Task<int> Insert(TEntity entity, bool immediatelySave = false)
        {
            // 如果需要立即保存数据
            if (immediatelySave)
            {
                _collection.Insert(entity); // 立即插入数据库
                return 1; // 返回1表示成功
            }
            lock (_cache)
            {
                _cache.Add(entity); // 将单条数据加入缓存
            }
            _timer.Change(1000, Timeout.Infinite);
            return 1;
        }

        private void InsertDataFromCache(object state)
        {
            lock (_cache)
            {
                if (_cache.Any())
                {
                    _collection.InsertBulk(_cache); // 批量插入缓存数据
                    _cache.Clear(); // 清空缓存
                }
            }
        }

        public async Task<int> Insert(List<TEntity> entities)
        {
            return await Task.Run(() =>
            {
                _collection.InsertBulk(entities);
                return entities.Count;
            });
        }

        public async Task<int> Delete(Expression<Func<TEntity, bool>> whereExpression)
        {
            return await Task.Run(() =>
            {
                var result = _collection.DeleteMany(whereExpression);
                return result;
            });
        }

        public async Task<int> Update(TEntity entity)
        {
            return await Task.Run(() =>
            {
                var updated = _collection.Update(entity);
                return updated ? 1 : 0;
            });
        }

        public async Task<int> UpdateColumns(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TEntity>> updateColumns)
        {
            return await Task.Run(() =>
            {
                var entities = _collection.Find(whereExpression);
                int updatedCount = 0;

                foreach (var entity in entities)
                {
                    // Apply updates to the entity here using the updateColumns expression
                    // This is a simple approach, depending on your needs you may want a more complex way
                    // to handle column updates. For example, you can use reflection to apply the changes.

                    var updated = updateColumns.Compile().Invoke(entity);
                    if (_collection.Update(updated))
                        updatedCount++;
                }

                return updatedCount;
            });
        }

        public async Task<List<TEntity>> Query(Expression<Func<TEntity, bool>> whereExpression)
        {
            return await Task.Run(() =>
            {
                return _collection.Find(whereExpression).ToList();
            });
        }

        public async Task<List<TEntity>> QueryAsync(Expression<Func<TEntity, bool>> whereExpression)
        {
            return await Task.Run(() =>
            {
                return _collection.Find(whereExpression).ToList();
            });
        }

        public async Task<List<TEntity>> Query(Expression<Func<TEntity, bool>> whereExpression, int count)
        {
            return await Task.Run(() =>
            {
                return _collection.Find(whereExpression).Take(count).ToList();  // 使用 Take 替代 Limit
            });
        }

        public async Task<List<TEntity>> QueryAsync(Expression<Func<TEntity, bool>> whereExpression, int count)
        {
            return await Task.Run(() =>
            {
                return _collection.Find(whereExpression).Take(count).ToList();  // 使用 Take 替代 Limit
            });
        }


        public async Task<(List<TEntity>, int, int)> Query(Expression<Func<TEntity, bool>> whereExpression, int page, int size)
        {
            return await Task.Run(() =>
            {
                var totalItems = _collection.Count(whereExpression);
                var items = _collection.Find(whereExpression).Skip((page - 1) * size).Take(size).ToList();
                var totalPages = (int)Math.Ceiling((double)totalItems / size);
                return (items, totalItems, totalPages);
            });
        }

        public async Task<(List<TEntity>, int, int)> QueryAsync(Expression<Func<TEntity, bool>> whereExpression, int page, int size)
        {
            return await Task.Run(() =>
            {
                var totalItems = _collection.Count(whereExpression);
                var items = _collection.Find(whereExpression).Skip((page - 1) * size).Take(size).ToList();
                var totalPages = (int)Math.Ceiling((double)totalItems / size);
                return (items, totalItems, totalPages);
            });
        }

        public async Task<List<string>> GetTableStringList()
        {
            return await Task.Run(() =>
            {
                return _db.GetCollectionNames().ToList();
            });
        }

        public async Task BackupDatabase(string backupFilePath)
        {
            await Task.Run(() =>
            {
                // 获取当前数据库文件路径
                string dbFilePath = _connectionString;

                // 检查备份文件路径是否存在，避免覆盖现有备份
                if (File.Exists(backupFilePath))
                {
                    throw new Exception("备份文件已存在，请选择其他位置");
                }

                // 复制数据库文件到备份路径
                File.Copy(dbFilePath, backupFilePath);
            });
        }

        public async Task RecoveryDatabase(string backupFilePath)
        {
            await Task.Run(() =>
            {
                // 获取当前数据库文件路径
                string dbFilePath = _connectionString;

                // 检查备份文件是否存在
                if (!File.Exists(backupFilePath))
                {
                    throw new Exception("备份文件不存在，请检查路径");
                }

                // 删除当前数据库文件（小心，删除前最好备份现有数据库）
                if (File.Exists(dbFilePath))
                {
                    _db.Dispose();
                    File.Delete(dbFilePath);
                }

                // 从备份文件恢复数据库
                File.Copy(backupFilePath, dbFilePath);

                _db = new LiteDatabase(_connectionString);
                _collection = _db.GetCollection<TEntity>(typeof(TEntity).Name);
            });
        }

    }
}
